package encaps.entities;

import encaps.utils.DatabaseUtil;
import encaps.utils.MD5Hash;
import encaps.utils.StringUtil;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.sql.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import javax.ejb.*;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class User implements EntityBean {

    public static final String TABLE_NAME = "User";
    public static final String LOGIN = "login";
    public static final String PIC = "pic";
    public static final String PASS = "pass";
    public static final String INFO = "info";
    public static final String ROLE = "role";
    public static final String EMAIL = "email";
    public static final String CONTACTS = "contacts";
    private EntityContext context;
    private DataSource dataSource;
    private boolean isEdited;
    private Long id;
    private String login;
    private String pic;
    private String info;
    private String role;
    private String email;
    private String contacts;
    private String pass;
    private HashMap<Long, Double> userRates;
    private HashMap<Long, Long> userComments;

    public void setEntityContext(EntityContext aContext) {
        context = aContext;
        try {
            dataSource = DatabaseUtil.getDataSource();
            isEdited = false;
        } catch (NamingException e) {
            throw new EJBException("DataSource lookup error", e);
        }
    }

    public Long ejbCreate(String login, String avatar, String info, String contacts,
            String password, String email, String role) throws CreateException {
        PreparedStatement insertValuesQuery = null;
        PreparedStatement selectIdQuery = null;
        Connection conn = null;
        try {
            this.pic = avatar;
            this.login = login;
            this.info = info;
            this.contacts = contacts;
            this.pass = MD5Hash.getHash(password);
            this.email = email;
            this.role = role;


            conn = dataSource.getConnection();
            insertValuesQuery = conn.prepareStatement("INSERT INTO user(login, pass, info, role, email, contacts, pic) VALUES(?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
            insertValuesQuery.setString(1, this.login);
            insertValuesQuery.setString(2, this.pass);
            insertValuesQuery.setString(3, this.info);
            insertValuesQuery.setString(4, this.role);
            insertValuesQuery.setString(5, this.email);
            insertValuesQuery.setString(6, this.contacts);
            insertValuesQuery.setString(7, this.pic);


            if (insertValuesQuery.executeUpdate() != 1) {
                throw new CreateException("Insertion error");
            }
            ResultSet generatedIdRS = insertValuesQuery.getGeneratedKeys();
            if (!generatedIdRS.next()) {
                throw new CreateException("Insertion error");
            }
            id = generatedIdRS.getLong(1);

            isEdited = false;
            return id;
        } catch (Exception ex) {
            throw new EJBException("Error in User.ejbCreate method", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, selectIdQuery);
            DatabaseUtil.closeConnection(null, insertValuesQuery);
        }

    }

    public void ejbPostCreate(String login, String avatar, String info, String contacts,
            String password, String email, String role) throws CreateException {
    }

    //привет лунатикам
    public void ejbActivate() {
    }

    public void ejbPassivate() {
    }

    public void ejbRemove() throws RemoveException {
        PreparedStatement ps = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("DELETE FROM user WHERE id=?");
            ps.setLong(1, id);
            if (ps.executeUpdate() < 1) {
                throw new RemoveException("Deletion error. Id=" + id);
            }
            isEdited = false;
        } catch (SQLException ex) {
            throw new EJBException("Error in User.ejbRemove method", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public void unsetEntityContext() {
        context = null;
    }

    public void ejbLoad() {
        id = (Long) context.getPrimaryKey();
        PreparedStatement ps = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("SELECT login, pass, pic, info, role, email, contacts FROM user WHERE id=?");
            ps.setLong(1, id);
            ResultSet rs = ps.executeQuery();
            if (!rs.next()) {
                throw new NoSuchEntityException("No user found by id = " + id);
            }
            login = rs.getString(LOGIN);
            pass = rs.getString(PASS);
            pic = rs.getString(PIC);
            info = rs.getString(INFO);
            role = rs.getString(ROLE);
            email = rs.getString(EMAIL);
            contacts = rs.getString(CONTACTS);
            ps = conn.prepareStatement("SELECT movie_id, rating FROM user_rating WHERE user_id=?");
            ps.setLong(1, id);
            rs = ps.executeQuery();
            userRates = new HashMap();
            while (rs.next()) {
                userRates.put(rs.getLong(1), rs.getDouble(2));
            }
            ps = conn.prepareStatement("SELECT id, movie_id FROM comment WHERE user_id=?");
            ps.setLong(1, id);
            rs = ps.executeQuery();
            userComments = new HashMap();
            while (rs.next()) {
                userComments.put(rs.getLong(1), rs.getLong(2));
            }

            isEdited = false;
        } catch (SQLException ex) {
            throw new EJBException("Error in User.ejbLoad method", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public void ejbStore() {
        if (!isEdited) {
            return;
        }
        PreparedStatement ps = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("UPDATE user SET login=?,pass=?, pic=?, info=?, role=?, email=?, contacts=? WHERE id=?");
            ps.setString(1, login);
            ps.setString(2, pass);
            ps.setString(3, pic);
            ps.setString(4, info);
            ps.setString(5, role);
            ps.setString(6, email);
            ps.setString(7, contacts);
            ps.setLong(8, id);
            if (ps.executeUpdate() < 1) {
                throw new NoSuchEntityException("No user found by id = " + id);
            }
            isEdited = false;
        } catch (SQLException ex) {
            throw new EJBException("Error in User.ejbStore method", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public java.lang.Long ejbFindByPrimaryKey(Long key) throws FinderException {
        PreparedStatement ps = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("SELECT id FROM user WHERE id=?;");
            ps.setLong(1, key);
            ResultSet rs = ps.executeQuery();
            if (!rs.next()) {
                throw new ObjectNotFoundException("No user found by primary key = " + key);
            }
            return key;
        } catch (SQLException ex) {
            throw new EJBException("Error in User.ejbFindByPrimaryKey method", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public Long ejbFindByLogin(String login) throws FinderException {

        PreparedStatement ps = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("SELECT id FROM user WHERE login=?");
            ps.setString(1, login);
            ResultSet rs = ps.executeQuery();
            if (!rs.next()) {
                throw new ObjectNotFoundException("No user found by login = " + login);
            }
            return rs.getLong(1);
        } catch (SQLException ex) {
            throw new EJBException("Error in User.ejbFindByLogin method", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public Integer ejbHomeGetUsersCount(String login) throws FinderException {
        PreparedStatement ps = null;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("SELECT Count(id) FROM user WHERE login LIKE ?");
            ps.setString(1, StringUtil.getLikePattern(login));
            ResultSet rs = ps.executeQuery();
            rs.first();
            return rs.getInt(1);
        } catch (SQLException ex) {
            throw new EJBException("Error in User.getUsersCount method", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public Collection ejbFindAll() {
        PreparedStatement ps = null;
        Connection conn = null;

        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("SELECT id FROM User");
            Collection keys = new LinkedList();
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                keys.add(rs.getLong(1));
            }
            return keys;
        } catch (SQLException ex) {
            throw new EJBException("Error in User.ejbFindAll method", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public Collection ejbFindPaged(String login, String sortColumn,
            OrderType orderType, Integer from, Integer count) {
        PreparedStatement ps = null;
        Connection conn = null;

        try {
            conn = dataSource.getConnection();
            String queryString = "SELECT id FROM User WHERE login LIKE ? %s LIMIT ?, ?";

            String orderClause = null;
            if (!StringUtil.isEmpty(sortColumn)) {
                StringBuilder sb = new StringBuilder();
                sb.append("ORDER BY ");
                sb.append(sortColumn);
                if (orderType.toString() != null) {
                    sb.append(" ");
                    sb.append(orderType.toString());
                }
                sb.append(" ");
                orderClause = sb.toString();
            } else {
                orderClause = "";
            }
            queryString = String.format(queryString, orderClause);
            ps = conn.prepareStatement(queryString);
            ps.setString(1, StringUtil.getLikePattern(login));
            ps.setInt(2, from);
            ps.setInt(3, count);
            Collection keys = new LinkedList();
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                keys.add(rs.getLong(1));
            }
            return keys;
        } catch (SQLException ex) {
            throw new EJBException("Error in User.ejbFindAllPaged method", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public Collection ejbFindPaged(String login, Integer from, Integer count) {
        PreparedStatement ps = null;
        Connection conn = null;

        try {
            conn = dataSource.getConnection();
            ps = conn.prepareStatement("SELECT id FROM User WHERE login LIKE ? LIMIT ?, ?");
            ps.setString(1, StringUtil.getLikePattern(login));
            ps.setInt(2, from);
            ps.setInt(3, count);
            Collection keys = new LinkedList();
            ResultSet rs = ps.executeQuery();
            while (rs.next()) {
                keys.add(rs.getLong(1));
            }
            return keys;
        } catch (SQLException ex) {
            throw new EJBException("Error in User.ejbFindAllPaged method", ex);
        } finally {
            DatabaseUtil.closeConnection(conn, ps);
        }
    }

    public Long getID() {
        return id;
    }

    public String getLogin() {
        return login;
    }

    public void setLogin(String value) {
        this.login = value;
        isEdited = true;
    }

    public String getAvatar() {
        return pic;
    }

    public void setAvatar(String value) {
        this.pic = value;
        isEdited = true;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String value) {
        this.info = value;
        isEdited = true;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String value) {
        this.role = value;
        isEdited = true;
    }

    public void setRole(Role r) {
        this.role = r.getRoleName();
        isEdited = true;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String value) {
        this.email = value;
        isEdited = true;
    }

    public String getContacts() {
        return contacts;
    }

    public void setContacts(String value) {
        this.contacts = value;
        isEdited = true;

    }

    public String getPasswordHash() {
        return pass;
    }

    public void setPassword(String value) throws NoSuchAlgorithmException,
            UnsupportedEncodingException {
        this.pass = MD5Hash.getHash(value);
        isEdited = true;
    }

    public HashMap getUserRates() {
        return userRates;
    }

    public HashMap getUserComments() {
        return userComments;
    }
    // </editor-fold>
}
